// 
//  MainWindow.cs
//  
//  Author:
//       Nikita Tsukanov <keks9n@gmail.com>
// 
//  Copyright (c) 2011 Nikita Tsukanov
// 
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//  GNU General Public License for more details.
//  
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 


using System;
using Gtk;
namespace SkypeTab
{
	public partial class MainWindow : Gtk.Window
	{

		private System.Diagnostics.Process m_SkypeProcess;
		private System.Collections.Generic.Dictionary<Int64,ManagedWindow> Windows=
			new System.Collections.Generic.Dictionary<Int64, ManagedWindow> ();
		Gdk.Display m_GdkDisplay;
		Timer m_Timer;
		Timer m_BlinkTimer;
		DummyWindow m_Dummy;
		ClipboardSync m_ClipSync;
		Gtk.StatusIcon m_Tray;
		
		bool UpdatingWindows;
		bool NeedBlinkIcon;
		bool m_WindowHidden;
		
		private Gdk.Pixbuf NormalIcon, UrgentIcon;
	

	
		private void PrepareIcon ()
		{
			var SkypeIcon=System.Drawing.Bitmap.FromFile("/usr/share/pixmaps/skype.png");
			System.IO.Stream stream=
				System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("SkypeTab.img.icon_mod.png");
			var IconMod=System.Drawing.Bitmap.FromStream(stream);
			var tmp= System.Drawing.Graphics.FromImage((System.Drawing.Image)SkypeIcon);
			int size=SkypeIcon.Width/2;
			tmp.DrawImage(IconMod, size,size,size,size);
			stream= new System.IO.MemoryStream();
			SkypeIcon.Save( stream,System.Drawing.Imaging.ImageFormat.Png);
			stream.Seek(0,System.IO.SeekOrigin.Begin);
			UrgentIcon=new Gdk.Pixbuf(stream);
		}
		
		public MainWindow () : base(Gtk.WindowType.Toplevel)
		{
			this.Build ();
			
			//We need it because if skype thinks that it's window is on top it doesn't 
			//set this window in urgent state. So just use our dummy window to make
			//skype think that it's not on top
			this.FocusInEvent+= delegate {
				m_WindowHidden=false;
				if(m_Dummy!=null)
				{
					Xephyr.X11.LowerWindow(m_Dummy.Handle);
				}
			};
			this.FocusOutEvent+= delegate {
				if(m_Dummy!=null)
				{
					Xephyr.X11.RaiseWindow(m_Dummy.Handle);
					Xephyr.X11.SetInputFocus(m_Dummy.Handle);
				}
			};
			
			Xephyr.OnStarted+= HandleXephyrOnStarted;
			Tabs.PageSelect+= HandleTabsPageSelect;
			Tabs.PageClose+= HandleTabsPageClose;
			Tabs.CanFocus=false;
			NormalIcon = new Gdk.Pixbuf ("/usr/share/pixmaps/skype.png");
			PrepareIcon();
			this.Icon=NormalIcon;

			
			m_Tray=new StatusIcon();
			m_Tray.Pixbuf=NormalIcon;
			m_Tray.Activate+= HandleM_TrayActivate;
			
			btnMenu.Clicked+= delegate {
				AboutDialog.Instance.Show();
				AboutDialog.Instance.Present();
			};
			
			Gtk.Timeout.Add(2000,delegate ()
			{
				if(Xephyr.X11==null)
				{
					this.Destroy();
					Xephyr.Dispose();
					Dispose();
					Application.Quit();
					MainClass.ShowError("Unable to launch Xephyr, see console log for details.");
				}
				return false;
			});
		}

		void HandleM_TrayActivate (object sender, EventArgs e)
		{
			m_WindowHidden=false;
			this.Show();
			this.Present();
		}

		

		void HandleTabsPageClose (object sender, Pager.PageInfo page)
		{
			if(UpdatingWindows) return;
			var win=(ManagedWindow)page.Tag;
			win.Destroy();
			
		}

		void HandleTabsPageSelect (object sender, Pager.PageInfo page)
		{
			
			if(UpdatingWindows) return;
			var win=(ManagedWindow)page.Tag;
			
			win.MoveAndResize(0,0,Xephyr.DisplayWidth, Xephyr.DisplayHeight);
			win.Raise();
			win.SetFocus();
			
			
		}

		void SkypeWatchdog()
		{
			m_SkypeProcess.WaitForExit();
			Gtk.Application.Invoke(delegate{
					Console.WriteLine("Skype terminated. Exiting...");
					AutoDestruct();
			});
			
			
		}
		
		void HandleXephyrOnStarted (object sender, EventArgs e)
		{
			m_Dummy=new DummyWindow(Xephyr.DisplayName);
			m_SkypeProcess=ProcessUtil.Start("skype","",false,false,false,Xephyr.DisplayName);
			var th=new System.Threading.Thread(SkypeWatchdog);
			th.IsBackground=true;
			th.Start();
			
			m_GdkDisplay=Gdk.Display.Open(Xephyr.DisplayName);
			m_ClipSync=new ClipboardSync(Gdk.Display.Default,m_GdkDisplay);
			m_Timer=new Timer(RescanWindows, 200);
			m_BlinkTimer=new Timer(BlinkIcon,1000);
			
			
			
		}
		
		private void AddWindow(long Handle, string Name)
		{
			btnMenu.Visible=true;
			var mv=new ManagedWindow(new System.IntPtr(Handle), Xephyr.X11, m_GdkDisplay);
			Windows.Add(Handle, mv);
			if(System.Text.RegularExpressions.Regex.Match(Name, "Skype.*(Beta)").Value.Length>0)
			{
				Tabs.AddTab(Name,mv,0).CloseButton.Visible=false;
				
			}
			else
				Tabs.AddTab(Name,mv);
			UpdateWindow(Handle,Name);
		}
		private void UpdateWindow(long Handle, string Name)
		{
			var page=Tabs.GetPageInfo(Windows[Handle]);
			if(page!=null)
			{
				page.Text=Name;
				page.Notify.Visible=Name.StartsWith("*");
				
			}
			else
				Windows.Remove(Handle);
			
		}
		private void DeleteWindow(long Handle)
		{
			var mv=Windows[Handle];
			if(Tabs.ContainsTag(mv))
				Tabs.RemovePageByTag(mv);
			Windows.Remove(Handle);
		}
		
		void BlinkIcon(object o, EventArgs e)
		{
			if(!NeedBlinkIcon)
				this.Icon=NormalIcon;
			else
			{
				if(this.Icon==NormalIcon)
					this.Icon=UrgentIcon;
				else
					this.Icon=NormalIcon;
			}
			
			if(SkypeApi.GetMissedCount()>0)
				m_Tray.Pixbuf=UrgentIcon;
			else
				m_Tray.Pixbuf=NormalIcon;
			
		}
		
		void RescanWindows(object o, EventArgs e)
		{
			
			m_ClipSync.Sync();
			
			try
			{
				bool found_no_redirect;
				var list=Xephyr.X11.GetTopLevels(out found_no_redirect);
				var ids=new System.Collections.Generic.List<long>();
				long topwin=0;
				
				
				bool foundnew=false;
				
	
				bool found_urgent=false;
				foreach(var entry in list)
				{
					long h=entry.ToInt64();
					if(entry==m_Dummy.Handle)
					{
						topwin=h;
						continue;
					}
	
					if(!foundnew)
					{	
						topwin=h;
					}
					string name=Xephyr.X11.GetWindowName(entry);
					if(name==null)
						name="<unk>";
					if(name.StartsWith("*"))
						found_urgent=true;
					
					if(!Windows.ContainsKey(h))
					{
						foundnew=true;
						AddWindow(h, name);
					}
					else UpdateWindow(h, name);
					ids.Add(h);
	
				}
				var to_delete=new System.Collections.Generic.List<long>();
				foreach(var mw in Windows)
				{
					if(!ids.Contains(mw.Key))
						to_delete.Add(mw.Key);
				}
				foreach(var tdi in to_delete)
				{
					DeleteWindow(tdi);		
				}
				
				
				
				UrgencyHint=found_urgent;
				NeedBlinkIcon=found_urgent;
				
				if(topwin==0) return;
				if(!Windows.ContainsKey(topwin))
					return;
				var mv=Windows[topwin];
				Tabs.ActivatePageByTag(mv);

				
				
				string tname=mv.Name;
				if(tname!=null)
					Title=tname;
				
		
				if(found_no_redirect) return;
				
				mv.MoveAndResize(0,0, Xephyr.DisplayWidth, Xephyr.DisplayHeight);
				mv.Raise();
				mv.SetFocus();
			}
			finally
			{
				UpdatingWindows=false;
			}
		}
		
		
		protected override bool OnDeleteEvent (Gdk.Event evnt)
		{
			if(!m_WindowHidden)
			{
				Hide();
				m_WindowHidden=true;
				int i=0;
				while(i<Tabs.Count)
				{
					if(!Tabs.GetPageInfo(i).CloseButton.Visible)
						i++;
					else
					{
						Tabs.ClosePage(i);
					}
				}
				return true;
			}
			
			AutoDestruct();
			return true;
		}
		
		void AutoDestruct()
		{
						
			m_Timer.Dispose();
			m_BlinkTimer.Dispose();
			
			Xephyr.Dispose();
			try
			{
				m_SkypeProcess.Kill();
			}
			catch
			{}
			Application.Quit();
		}
		
	}
}

